Amazon ElastiCache for RedisからAmazon ElastiCache for Valkeyに変更してみた
以下の記事で紹介されている通り、RedisキャッシュからValkeyキャッシュへ変更することが可能ということで試してみました。
やること
上記の記事では「ダウンタイムゼロの移行」と記載されていましたので、変更中に接続が可能なのかと変更前に登録されていたデータがどうなるのかという部分を確認してみます。
変更中の接続確認は安直ですが、redis-cliでpingを実行し続けて変更途中で失敗しているものが無いかというのを確認してみます。
nohup bash -c 'while true; do printf "%s | " "$(date)"; redis-cli -h プライマリエンドポイント -p 6379 ping; done' >> connect.txt &
変更後のデータ確認は変更前に以下のredis-cliコマンドでデータを登録して変更後に同じ値が取得できるか確認します。
redis-cli -h プライマリエンドポイント -p 6379 mset name:1 "kobayashi1" name:2 "kobayashi2" name:3 "kobayashi3"
以下のコマンドを実行した際に「"kobayashi1"」、「"kobayashi2"」、「"kobayashi3"」という値が取得できることを確認します。
redis-cli -h プライマリエンドポイント -p 6379 mget name:1 name:2 name:3
環境作成
まずは実行環境の作成を行います。
AWSリソースの作成は以下のCloudFormationテンプレートで行いました。
AWSTemplateFormatVersion: "2010-09-09"
Description: test Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for VPC
Parameters:
- VPCCIDR
- Label:
default: Parameters for Subnet
Parameters:
- PublicSubnet01CIDR
- PublicSubnet02CIDR
- Label:
default: Parameters for ec2
Parameters:
- EC2VolumeSize
- EC2VolumeIOPS
- EC2AMI
- EC2InstanceType
- Label:
default: Parameters for ElastiCache
Parameters:
- ElastiCacheNodeType
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
VPCCIDR:
Default: 172.30.0.0/16
Type: String
PublicSubnet01CIDR:
Default: 172.30.0.0/24
Type: String
PublicSubnet02CIDR:
Default: 172.30.1.0/24
Type: String
EC2VolumeSize:
Default: 32
Type: Number
EC2VolumeIOPS:
Default: 3000
Type: Number
EC2AMI:
Type : AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64
EC2InstanceType:
Default: t3.medium
Type: String
ElastiCacheNodeType:
Default: cache.t4g.small
Type: String
Resources:
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
EC2IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
RoleName: iam-role-ec2
Tags:
- Key: Name
Value: iam-role-ec2
EC2IAMInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: iam-instanceprofile-ec2
Roles:
- !Ref EC2IAMRole
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: test-vpc
# ------------------------------------------------------------#
# InternetGateway
# ------------------------------------------------------------#
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub test-igw
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
# ------------------------------------------------------------#
# Subnet
# ------------------------------------------------------------#
PublicSubnet01:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PublicSubnet01CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub test-public-subnet-01
VpcId: !Ref VPC
PublicSubnet02:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1c
CidrBlock: !Ref PublicSubnet02CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub test-public-subnet-02
VpcId: !Ref VPC
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: test-public-rtb
PublicRouteTableRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
RouteTableId: !Ref PublicRouteTable
PublicRtAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet01
PublicRtAssociation2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet02
# ------------------------------------------------------------#
# Security Group
# ------------------------------------------------------------#
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for ec2
GroupName: test-sg-ec2
Tags:
- Key: Name
Value: test-sg-ec2
VpcId: !Ref VPC
ElasticacheSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for Redis
GroupName: test-sg-elasticache
SecurityGroupIngress:
- IpProtocol: tcp
SourceSecurityGroupId: !Ref EC2SG
FromPort: 6379
ToPort: 6379
Tags:
- Key: Name
Value: test-sg-elasticache
VpcId: !Ref VPC
# ------------------------------------------------------------#
# EC2
# ------------------------------------------------------------#
EC2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: !Ref EC2VolumeIOPS
VolumeSize: !Ref EC2VolumeSize
VolumeType: gp3
DisableApiTermination: false
IamInstanceProfile: !Ref EC2IAMInstanceProfile
ImageId: !Ref EC2AMI
InstanceType: !Ref EC2InstanceType
SecurityGroupIds:
- !Ref EC2SG
SubnetId: !Ref PublicSubnet01
Tags:
- Key: Name
Value: test-ec2
UserData: !Base64 |
#!/bin/bash
dnf install gcc openssl-devel -y
curl -s http://download.redis.io/redis-stable.tar.gz -o redis-stable.tar.gz
tar zxf redis-stable.tar.gz
cd redis-stable/
make redis-cli BUILD_TLS=yes
install -m 0755 src/redis-cli /usr/local/bin/
# ------------------------------------------------------------#
# Elasticache
# ------------------------------------------------------------#
ElastiCacheSubnetGroup:
Type: AWS::ElastiCache::SubnetGroup
Properties:
CacheSubnetGroupName: test-cache-subunet
Description: Redis Subnet Group
SubnetIds:
- !Ref PublicSubnet01
- !Ref PublicSubnet02
ElastiCacheParameterGroup:
Type: AWS::ElastiCache::ParameterGroup
Properties:
Description: ElastiCacheParameterGroup
CacheParameterGroupFamily: redis7
ElastiCacheCluster:
Type: AWS::ElastiCache::ReplicationGroup
Properties:
CacheNodeType: !Ref ElastiCacheNodeType
CacheParameterGroupName: !Ref ElastiCacheParameterGroup
CacheSubnetGroupName: !Ref ElastiCacheSubnetGroup
Engine: Redis
EngineVersion: 7.1
MultiAZEnabled: true
NumCacheClusters: 2
Port: 6379
ReplicationGroupDescription: Redis Cluster
ReplicationGroupId: test-elasticache-redis
SecurityGroupIds:
- !Ref ElasticacheSG
Tags:
- Key: Name
Value: test-elasticache-redis
上記のCloudFormationテンプレートで作成しているリソースは接続確認用EC2インスタンスとElastiCache for Redisになります。
デプロイは以下のAWS CLIコマンドを実行します。
デプロイ完了までに10分~15分程度かかります。(ElastiCacheの作成に少し時間がかかります)
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --capabilities CAPABILITY_NAMED_IAM
Valkeyへ変更
下準備
AWSリソースの作成が完了したらEC2インスタンスへ接続して下準備を行います。
EC2へはSystems Manager Session Managerで接続できるようにIAMロールなどの設定を行っていますので、以下のドキュメントの手順で接続してください。
EC2へ接続ができたら以下のコマンドを実行してElastiCache for Redisに接続できることを確認します。
接続に成功していると「PONG」という出力が確認できます。
redis-cli -h プライマリエンドポイント -p 6379 ping
接続確認ができたら以下のコマンドでデータを登録します。
redis-cli -h プライマリエンドポイント -p 6379 mset name:1 "kobayashi1" name:2 "kobayashi2" name:3 "kobayashi3"
コマンドを実行したら以下のコマンドで登録されていることを確認します。
redis-cli -h プライマリエンドポイント -p 6379 mget name:1 name:2 name:3
登録されていることが確認できたら以下のコマンドを実行します。
プロセスを消すまで「connect.txt」というファイルにpingの実行結果を書き込み続けます。
nohup bash -c 'while true; do printf "%s | " "$(date)"; redis-cli -h プライマリエンドポイント -p 6379 ping; done' >> connect.txt &
Valkeyへ変更
接続確認用EC2で下準備が完了したら実際にValkeyへ変更していきます。
ElastiCacheのコンソールへ移動して左のメニューから「Redis OSS キャッシュ」をクリックします。
クリック後、CloudFormationで作成したRedisクラスターを選択します。
選択後、「アクション」から「変更」をクリックします。
画面遷移後、「クラスター設定」欄にある「モード」を「Valkey」へ変更します。
この際にデフォルトのパラメータグループ以外を設定したい場合は事前にValkey用のパラメータグループを作成しておいてください。
モードを選択したら画面下までスクロールして「変更をプレビュー」をクリックします。
画面遷移後、「変更の概要」欄で「エンジン」が「Valkey」になっていること、「すぐに適用」のチェックボックスにチェックが入っていることを確認したら「変更」をクリックします。
変更をクリック後、ステータスがModifyingになります。
変更が完了すると「Valkey キャッシュ」の画面から確認できるようになります。(変更完了までには20分程度かかりました)
変更が完了したらEC2で実行していたコマンドを停止します。(他にバックグラウンドジョブを実行していなければ以下のコマンドで停止します)
kill -s SIGKILL %1
コマンドを停止したら以下のコマンドで「connect.txt」の行数と「PONG」という文字列が入っている行数が一致するか確認します。
[ "$(cat connect.txt | wc -l)" = "$(grep "PONG" connect.txt | wc -l)" ] && echo "一致しています。" || { echo "一致していません。"; echo "総行数: $(cat connect.txt | wc -l)"; echo "PONG を含む行数: $(grep "PONG" connect.txt | wc -l)"; }
結果としては特にエラー無くpingが成功しているようでした。
[ssm-user@ip-172-30-0-92 ~]$ [ "$(cat connect.txt | wc -l)" = "$(grep "PONG" connect.txt | wc -l)" ] && echo "一致しています。" || { echo "一致していません。"; echo "総行数: $(cat connect.txt | wc -l)"; echo "PONG を含む行数: $(grep "PONG" connect.txt | wc -l)"; }
一致しています。
[ssm-user@ip-172-30-0-92 ~]$ cat connect.txt | wc -l
117305
[ssm-user@ip-172-30-0-92 ~]$ grep "PONG" connect.txt | wc -l
117305
次に変更前に登録していたデータがどのようになっているか以下のコマンドで確認します。
redis-cli -h プライマリエンドポイント -p 6379 mget name:1 name:2 name:3
結果としては変更前に登録していたデータはそのまま残っていました。
[ssm-user@ip-172-30-0-92 ~]$ redis-cli -h test-elasticache-redis.6fkmjm.ng.0001.apne1.cache.amazonaws.com -p 6379 mget name:1 name:2 name:3
1) "kobayashi1"
2) "kobayashi2"
3) "kobayashi3"
さいごに
今回はRedisキャッシュからValkeyキャッシュへの変更を試してみました。
検証の結果としては変更中も接続は可能となっていて変更後もデータは残っていました。
今回の検証はかなり簡易的なものとなっています。
皆様のワークロードによっては結果が変わる可能性があるので、本番環境等の変更を行う場合は必ず事前に検証を行ってください。